home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xlock / xlock.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  23KB  |  788 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)xlock.c    23.21 91/06/27 XLOCK";
  3. #endif
  4. /*-
  5.  * xlock.c - X11 client to lock a display and show a screen saver.
  6.  *
  7.  * Copyright (c) 1988-91 by Patrick J. Naughton.
  8.  *
  9.  * Permission to use, copy, modify, and distribute this software and its
  10.  * documentation for any purpose and without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and that
  12.  * both that copyright notice and this permission notice appear in
  13.  * supporting documentation.
  14.  *
  15.  * This file is provided AS IS with no warranties of any kind.  The author
  16.  * shall have no liability with respect to the infringement of copyrights,
  17.  * trade secrets or any patents by this file or any part thereof.  In no
  18.  * event will the author be liable for any lost revenue or profits or
  19.  * other special, indirect and consequential damages.
  20.  *
  21.  * Comments and additions should be sent to the author:
  22.  *
  23.  *               naughton@eng.sun.com
  24.  *
  25.  *               Patrick J. Naughton
  26.  *               MS 21-14
  27.  *               Sun Laboritories, Inc.
  28.  *               2550 Garcia Ave
  29.  *               Mountain View, CA  94043
  30.  *
  31.  * Revision History:
  32.  * 24-Jun-91: make foreground and background color get used on mono.
  33.  * 24-May-91: added -usefirst.
  34.  * 16-May-91: added pyro and random modes.
  35.  *          ripped big comment block out of all other files.
  36.  * 08-Jan-91: fix some problems with password entry.
  37.  *          removed renicing code.
  38.  * 29-Oct-90: added cast to XFree() arg.
  39.  *          added volume arg to call to XBell().
  40.  * 28-Oct-90: center prompt screen.
  41.  *          make sure Xlib input buffer does not use up all of swap.
  42.  *          make displayed text come from resource file for better I18N.
  43.  *          add backward compatible signal handlers for pre 4.1 machines.
  44.  * 31-Aug-90: added blank mode.
  45.  *          added swarm mode.
  46.  *          moved usleep() and seconds() out to usleep.c.
  47.  *          added SVR4 defines to xlock.h
  48.  * 29-Jul-90: added support for multiple screens to be locked by one xlock.
  49.  *          moved global defines to xlock.h
  50.  *          removed use of allowsig().
  51.  * 07-Jul-90: reworked commandline args and resources to use Xrm.
  52.  *          moved resource processing out to resource.c
  53.  * 02-Jul-90: reworked colors to not use dynamic colormap.
  54.  * 23-May-90: added autoraise when obscured.
  55.  * 15-Apr-90: added hostent alias searching for host authentication.
  56.  * 18-Feb-90: added SunOS3.5 fix.
  57.  *          changed -mono -> -color, and -saver -> -lock.
  58.  *          allow non-locking screensavers to display on remote machine.
  59.  *          added -echokeys to disable echoing of '?'s on input.
  60.  *          cleaned up all of the parameters and defaults.
  61.  * 20-Dec-89: added -xhost to allow access control list to be left alone.
  62.  *          added -screensaver (don't disable screen saver) for the paranoid.
  63.  *          Moved seconds() here from all of the display mode source files.
  64.  *          Fixed bug with calling XUngrabHosts() in finish().
  65.  * 19-Dec-89: Fixed bug in GrabPointer.
  66.  *          Changed fontname to XLFD style.
  67.  * 23-Sep-89: Added fix to allow local hostname:0 as a display.
  68.  *          Put empty case for Enter/Leave events.
  69.  *          Moved colormap installation later in startup.
  70.  * 20-Sep-89: Linted and made -saver mode grab the keyboard and mouse.
  71.  *          Replaced SunView code for life mode with Jim Graham's version,
  72.  *        so I could contrib it without legal problems.
  73.  *          Sent to expo for X11R4 contrib.
  74.  * 19-Sep-89: Added '?'s on input.
  75.  * 27-Mar-89: Added -qix mode.
  76.  *          Fixed GContext->GC.
  77.  * 20-Mar-89: Added backup font (fixed) if XQueryLoadFont() fails.
  78.  *          Changed default font to lucida-sans-24.
  79.  * 08-Mar-89: Added -nice, -mode and -display, built vector for life and hop.
  80.  * 24-Feb-89: Replaced hopalong display with life display from SunView1.
  81.  * 22-Feb-89: Added fix for color servers with n < 8 planes.
  82.  * 16-Feb-89: Updated calling conventions for XCreateHsbColormap();
  83.  *          Added -count for number of iterations per color.
  84.  *          Fixed defaulting mechanism.
  85.  *          Ripped out VMS hacks.
  86.  *          Sent to expo for X11R3 contrib.
  87.  * 15-Feb-89: Changed default font to pellucida-sans-18.
  88.  * 20-Jan-89: Added -verbose and fixed usage message.
  89.  * 19-Jan-89: Fixed monochrome gc bug.
  90.  * 16-Dec-88: Added SunView style password prompting.
  91.  * 19-Sep-88: Changed -color to -mono. (default is color on color displays).
  92.  *          Added -saver option. (just do display... don't lock.)
  93.  * 31-Aug-88: Added -time option.
  94.  *          Removed code for fractals to separate file for modularity.
  95.  *          Added signal handler to restore host access.
  96.  *          Installs dynamic colormap with a Hue Ramp.
  97.  *          If grabs fail then exit.
  98.  *          Added VMS Hacks. (password 'iwiwuu').
  99.  *          Sent to expo for X11R2 contrib.
  100.  * 08-Jun-88: Fixed root password pointer problem and changed PASSLENGTH to 20.
  101.  * 20-May-88: Added -root to allow root to unlock.
  102.  * 12-Apr-88: Added root password override.
  103.  *          Added screen saver override.
  104.  *          Removed XGrabServer/XUngrabServer.
  105.  *          Added access control handling instead.
  106.  * 01-Apr-88: Added XGrabServer/XUngrabServer for more security.
  107.  * 30-Mar-88: Removed startup password requirement.
  108.  *          Removed cursor to avoid phosphor burn.
  109.  * 27-Mar-88: Rotate fractal by 45 degrees clockwise.
  110.  * 24-Mar-88: Added color support. [-color]
  111.  *          wrote the man page.
  112.  * 23-Mar-88: Added HOPALONG routines from Scientific American Sept. 86 p. 14.
  113.  *          added password requirement for invokation
  114.  *          removed option for command line password
  115.  *          added requirement for display to be "unix:0".
  116.  * 22-Mar-88: Recieved Walter Milliken's comp.windows.x posting.
  117.  *
  118.  */
  119.  
  120. #include <stdio.h>
  121. #include <signal.h>
  122. #include <string.h>
  123. #include <pwd.h>
  124.  
  125. #include "xlock.h"
  126. #include <X11/cursorfont.h>
  127. #include <X11/Xatom.h>
  128.  
  129. extern char *crypt();
  130. extern char *getenv();
  131.  
  132. char       *ProgramName;    /* argv[0] */
  133. perscreen   Scr[MAXSCREENS];
  134. Display    *dsp = NULL;        /* server display connection */
  135. int         screen;        /* current screen */
  136. void        (*callback) () = NULL;
  137. void        (*init) () = NULL;
  138.  
  139. static int  screens;        /* number of screens */
  140. static Window win[MAXSCREENS];    /* window used to cover screen */
  141. static Window icon[MAXSCREENS];    /* window used during password typein */
  142. static Window root[MAXSCREENS];    /* convenience pointer to the root window */
  143. static GC   textgc[MAXSCREENS];    /* graphics context used for text rendering */
  144. static long fgcol[MAXSCREENS];    /* used for text rendering */
  145. static long bgcol[MAXSCREENS];    /* background of text screen */
  146. static int  iconx[MAXSCREENS];    /* location of left edge of icon */
  147. static int  icony[MAXSCREENS];    /* location of top edge of icon */
  148. static Cursor mycursor;        /* blank cursor */
  149. static Pixmap lockc;
  150. static Pixmap lockm;        /* pixmaps for cursor and mask */
  151. static char no_bits[] = {0};    /* dummy array for the blank cursor */
  152. static int  passx;        /* position of the ?'s */
  153. static int  passy;
  154. static XFontStruct *font;
  155. static int  sstimeout;        /* screen saver parameters */
  156. static int  ssinterval;
  157. static int  ssblanking;
  158. static int  ssexposures;
  159.  
  160. #define PASSLENGTH 20
  161. #define FALLBACK_FONTNAME    "fixed"
  162. #define ICONW            64
  163. #define ICONH            64
  164.  
  165. #define AllPointerEventMask \
  166.     (ButtonPressMask | ButtonReleaseMask | \
  167.     EnterWindowMask | LeaveWindowMask | \
  168.     PointerMotionMask | PointerMotionHintMask | \
  169.     Button1MotionMask | Button2MotionMask | \
  170.     Button3MotionMask | Button4MotionMask | \
  171.     Button5MotionMask | ButtonMotionMask | \
  172.     KeymapStateMask)
  173.  
  174.  
  175. /* VARARGS1 */
  176. void
  177. error(s1, s2)
  178.     char       *s1, *s2;
  179. {
  180.     fprintf(stderr, s1, ProgramName, s2);
  181.     exit(1);
  182. }
  183.  
  184. /*
  185.  * Server access control support.
  186.  */
  187.  
  188. static XHostAddress *XHosts;    /* the list of "friendly" client machines */
  189. static int  HostAccessCount;    /* the number of machines in XHosts */
  190. static Bool HostAccessState;    /* whether or not we even look at the list */
  191.  
  192. static void
  193. XGrabHosts(dsp)
  194.     Display    *dsp;
  195. {
  196.     XHosts = XListHosts(dsp, &HostAccessCount, &HostAccessState);
  197.     if (XHosts)
  198.     XRemoveHosts(dsp, XHosts, HostAccessCount);
  199.     XEnableAccessControl(dsp);
  200. }
  201.  
  202. static void
  203. XUngrabHosts(dsp)
  204.     Display    *dsp;
  205. {
  206.     if (XHosts) {
  207.     XAddHosts(dsp, XHosts, HostAccessCount);
  208.     XFree((char *) XHosts);
  209.     }
  210.     if (HostAccessState == False)
  211.     XDisableAccessControl(dsp);
  212. }
  213.  
  214.  
  215. /*
  216.  * Simple wrapper to get an asynchronous grab on the keyboard and mouse.
  217.  * If either grab fails, we sleep for one second and try again since some
  218.  * window manager might have had the mouse grabbed to drive the menu choice
  219.  * that picked "Lock Screen..".  If either one fails the second time we print
  220.  * an error message and exit.
  221.  */
  222. static void
  223. GrabKeyboardAndMouse()
  224. {
  225.     Status      status;
  226.  
  227.     status = XGrabKeyboard(dsp, win[0], True,
  228.                GrabModeAsync, GrabModeAsync, CurrentTime);
  229.     if (status != GrabSuccess) {
  230.     sleep(1);
  231.     status = XGrabKeyboard(dsp, win[0], True,
  232.                    GrabModeAsync, GrabModeAsync, CurrentTime);
  233.  
  234.     if (status != GrabSuccess)
  235.         error("%s: couldn't grab keyboard! (%d)\n", status);
  236.     }
  237.     status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
  238.               GrabModeAsync, GrabModeAsync, None, mycursor,
  239.               CurrentTime);
  240.     if (status != GrabSuccess) {
  241.     sleep(1);
  242.     status = XGrabPointer(dsp, win[0], True, AllPointerEventMask,
  243.                   GrabModeAsync, GrabModeAsync, None, mycursor,
  244.                   CurrentTime);
  245.  
  246.     if (status != GrabSuccess)
  247.         error("%s: couldn't grab pointer! (%d)\n", status);
  248.     }
  249. }
  250.  
  251.  
  252. /*
  253.  * Assuming that we already have an asynch grab on the pointer,
  254.  * just grab it again with a new cursor shape and ignore the return code.
  255.  */
  256. static void
  257. XChangeGrabbedCursor(cursor)
  258.     Cursor      cursor;
  259. {
  260. #ifndef DEBUG
  261.     (void) XGrabPointer(dsp, win[0], True, AllPointerEventMask,
  262.             GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
  263. #endif
  264. }
  265.  
  266.  
  267. /*
  268.  * Restore all grabs, reset screensaver, restore colormap, close connection.
  269.  */
  270. static void
  271. finish()
  272. {
  273.     XSync(dsp, False);
  274.     if (!nolock && !allowaccess)
  275.     XUngrabHosts(dsp);
  276.     XUngrabPointer(dsp, CurrentTime);
  277.     XUngrabKeyboard(dsp, CurrentTime);
  278.     if (!enablesaver)
  279.     XSetScreenSaver(dsp, sstimeout, ssinterval, ssblanking, ssexposures);
  280.     XFlush(dsp);
  281.     XCloseDisplay(dsp);
  282. }
  283.  
  284.  
  285. static int
  286. ReadXString(s, slen)
  287.     char       *s;
  288.     int         slen;
  289. {
  290.     XEvent      event;
  291.     char        keystr[20];
  292.     char        c;
  293.     int         i;
  294.     int         bp;
  295.     int         len;
  296.     int         thisscreen = screen;
  297.     char        pwbuf[PASSLENGTH];
  298.  
  299.     for (screen = 0; screen < screens; screen++)
  300.     if (thisscreen == screen)
  301.         init(icon[screen]);
  302.     else
  303.         init(win[screen]);
  304.     bp = 0;
  305.     *s = 0;
  306.     while (True) {
  307.     unsigned long lasteventtime = seconds();
  308.     while (!XPending(dsp)) {
  309.         for (screen = 0; screen < screens; screen++)
  310.         if (thisscreen == screen)
  311.             callback(icon[screen]);
  312.         else
  313.             callback(win[screen]);
  314.         XFlush(dsp);
  315.         usleep(delay);
  316.         if (seconds() - lasteventtime > timeout) {
  317.         screen = thisscreen;
  318.         return 1;
  319.         }
  320.     }
  321.     screen = thisscreen;
  322.     XNextEvent(dsp, &event);
  323.     switch (event.type) {
  324.     case KeyPress:
  325.         len = XLookupString((XKeyEvent *) & event, keystr, 20, NULL, NULL);
  326.         for (i = 0; i < len; i++) {
  327.         c = keystr[i];
  328.         switch (c) {
  329.         case 8:    /* ^H */
  330.         case 127:    /* DEL */
  331.             if (bp > 0)
  332.             bp--;
  333.             break;
  334.         case 10:    /* ^J */
  335.         case 13:    /* ^M */
  336.             s[bp] = '\0';
  337.             return 0;
  338.         case 21:    /* ^U */
  339.             bp = 0;
  340.             break;
  341.         default:
  342.             s[bp] = c;
  343.             if (bp < slen - 1)
  344.             bp++;
  345.             else
  346.             XSync(dsp, True);    /* flush input buffer */
  347.         }
  348.         }
  349.         XSetForeground(dsp, Scr[screen].gc, bgcol[screen]);
  350.         if (echokeys) {
  351.         memset(pwbuf, '?', slen);
  352.         XFillRectangle(dsp, win[screen], Scr[screen].gc,
  353.                    passx, passy - font->ascent,
  354.                    XTextWidth(font, pwbuf, slen),
  355.                    font->ascent + font->descent);
  356.         XDrawString(dsp, win[screen], textgc[screen],
  357.                 passx, passy, pwbuf, bp);
  358.         }
  359.         /*
  360.          * eat all events if there are more than enough pending... this
  361.          * keeps the Xlib event buffer from growing larger than all
  362.          * available memory and crashing xlock.
  363.          */
  364.         if (XPending(dsp) > 100) {    /* 100 is arbitrarily big enough */
  365.         register Status status;
  366.         do {
  367.             status = XCheckMaskEvent(dsp,
  368.                       KeyPressMask | KeyReleaseMask, &event);
  369.         } while (status);
  370.         XBell(dsp, 100);
  371.         }
  372.         break;
  373.  
  374.     case ButtonPress:
  375.         if (((XButtonEvent *) & event)->window == icon[screen]) {
  376.         return 1;
  377.         }
  378.         break;
  379.  
  380.     case VisibilityNotify:
  381.         if (event.xvisibility.state != VisibilityUnobscured) {
  382. #ifndef DEBUG
  383.         XRaiseWindow(dsp, win[screen]);
  384. #endif
  385.         s[0] = '\0';
  386.         return 1;
  387.         }
  388.         break;
  389.  
  390.     case KeymapNotify:
  391.     case KeyRelease:
  392.     case ButtonRelease:
  393.     case MotionNotify:
  394.     case LeaveNotify:
  395.     case EnterNotify:
  396.         break;
  397.  
  398.     default:
  399.         fprintf(stderr, "%s: unexpected event: %d\n",
  400.             ProgramName, event.type);
  401.         break;
  402.     }
  403.     }
  404. }
  405.  
  406.  
  407.  
  408. static int
  409. getPassword()
  410. {
  411.     char        buffer[PASSLENGTH];
  412.     char        userpass[PASSLENGTH];
  413.     char        rootpass[PASSLENGTH];
  414.     char       *user;
  415.     XWindowAttributes xgwa;
  416.     int         y, left, done;
  417.     struct passwd *pw;
  418.  
  419.     pw = getpwnam("root");
  420.     strcpy(rootpass, pw->pw_passwd);
  421.  
  422.     pw = getpwnam(cuserid(NULL));
  423.     strcpy(userpass, pw->pw_passwd);
  424.  
  425.     user = pw->pw_name;
  426.  
  427.     XGetWindowAttributes(dsp, win[screen], &xgwa);
  428.  
  429.     XChangeGrabbedCursor(XCreateFontCursor(dsp, XC_left_ptr));
  430.  
  431.     XSetForeground(dsp, Scr[screen].gc, bgcol[screen]);
  432.     XFillRectangle(dsp, win[screen], Scr[screen].gc,
  433.            0, 0, xgwa.width, xgwa.height);
  434.  
  435.     XMapWindow(dsp, icon[screen]);
  436.     XRaiseWindow(dsp, icon[screen]);
  437.  
  438.     left = iconx[screen] + ICONW + font->max_bounds.width;
  439.     y = icony[screen] + font->ascent;
  440.  
  441.     XDrawString(dsp, win[screen], textgc[screen],
  442.         left, y, text_name, strlen(text_name));
  443.     XDrawString(dsp, win[screen], textgc[screen],
  444.         left + 1, y, text_name, strlen(text_name));
  445.     XDrawString(dsp, win[screen], textgc[screen],
  446.         left + XTextWidth(font, text_name, strlen(text_name)), y,
  447.         user, strlen(user));
  448.  
  449.     y += font->ascent + font->descent + 2;
  450.     XDrawString(dsp, win[screen], textgc[screen],
  451.         left, y, text_pass, strlen(text_pass));
  452.     XDrawString(dsp, win[screen], textgc[screen],
  453.         left + 1, y, text_pass, strlen(text_pass));
  454.  
  455.     passx = left + 1 + XTextWidth(font, text_pass, strlen(text_pass))
  456.     + XTextWidth(font, " ", 1);
  457.     passy = y;
  458.  
  459.     y = icony[screen] + ICONH + font->ascent + 2;
  460.     XDrawString(dsp, win[screen], textgc[screen],
  461.         iconx[screen], y, text_info, strlen(text_info));
  462.  
  463.     XFlush(dsp);
  464.  
  465.     y += font->ascent + font->descent + 2;
  466.  
  467.     done = False;
  468.     while (!done) {
  469.     if (ReadXString(buffer, PASSLENGTH))
  470.         break;
  471.  
  472.     /*
  473.      * we don't allow for root to have no password, but we handle the case
  474.      * where the user has no password correctly; they have to hit return
  475.      * only
  476.      */
  477.  
  478.     done = !((strcmp(crypt(buffer, userpass), userpass))
  479.            && (!allowroot || strcmp(crypt(buffer, rootpass), rootpass)));
  480.  
  481.     if (!done && *buffer == '\0') {
  482.         /* just hit return, and it wasn't his password */
  483.         break;
  484.     }
  485.     if (*userpass == '\0' && *buffer != '\0') {
  486.         /*
  487.          * the user has no password, but something was typed anyway.
  488.          * sounds fishy: don't let him in...
  489.          */
  490.         done = False;
  491.     }
  492.     /* clear plaintext password so you can't grunge around /dev/kmem */
  493.     memset(buffer, 0, sizeof(buffer));
  494.  
  495.     XSetForeground(dsp, Scr[screen].gc, bgcol[screen]);
  496.  
  497.     XFillRectangle(dsp, win[screen], Scr[screen].gc,
  498.                iconx[screen], y - font->ascent,
  499.                XTextWidth(font, text_invalid, strlen(text_invalid)),
  500.                font->ascent + font->descent + 2);
  501.  
  502.     XDrawString(dsp, win[screen], textgc[screen],
  503.             iconx[screen], y, text_valid, strlen(text_valid));
  504.  
  505.     if (done)
  506.         return 0;
  507.     else {
  508.         XSync(dsp, True);    /* flush input buffer */
  509.         sleep(1);
  510.         XFillRectangle(dsp, win[screen], Scr[screen].gc,
  511.                iconx[screen], y - font->ascent,
  512.                XTextWidth(font, text_valid, strlen(text_valid)),
  513.                font->ascent + font->descent + 2);
  514.         XDrawString(dsp, win[screen], textgc[screen],
  515.             iconx[screen], y, text_invalid, strlen(text_invalid));
  516.         if (echokeys)    /* erase old echo */
  517.         XFillRectangle(dsp, win[screen], Scr[screen].gc,
  518.                    passx, passy - font->ascent,
  519.                    xgwa.width - passx,
  520.                    font->ascent + font->descent);
  521.     }
  522.     }
  523.     XChangeGrabbedCursor(mycursor);
  524.     XUnmapWindow(dsp, icon[screen]);
  525.     return 1;
  526. }
  527.  
  528.  
  529. static void
  530. justDisplay()
  531. {
  532.     XEvent      event;
  533.  
  534.     for (screen = 0; screen < screens; screen++)
  535.     init(win[screen]);
  536.     do {
  537.     while (!XPending(dsp)) {
  538.         for (screen = 0; screen < screens; screen++)
  539.         callback(win[screen]);
  540.         XFlush(dsp);
  541.         usleep(delay);
  542.     }
  543.     XNextEvent(dsp, &event);
  544. #ifndef DEBUG
  545.     if (event.type == VisibilityNotify)
  546.         XRaiseWindow(dsp, event.xany.window);
  547. #endif
  548.     } while (event.type != ButtonPress && event.type != KeyPress);
  549.     for (screen = 0; screen < screens; screen++)
  550.     if (event.xbutton.root == RootWindow(dsp, screen))
  551.         break;
  552.     if (usefirst)
  553.     XPutBackEvent(dsp, &event);
  554. }
  555.  
  556.  
  557. static void
  558. sigcatch()
  559. {
  560.     finish();
  561.     error("%s: caught terminate signal.\nAccess control list restored.\n");
  562. }
  563.  
  564.  
  565. static void
  566. lockDisplay()
  567. {
  568.     if (!allowaccess) {
  569. #ifdef SYSV
  570.     sigset_t    oldsigmask;
  571.     sigset_t    newsigmask;
  572.  
  573.     sigemptyset(&newsigmask);
  574.     sigaddset(&newsigmask, SIGHUP);
  575.     sigaddset(&newsigmask, SIGINT);
  576.     sigaddset(&newsigmask, SIGQUIT);
  577.     sigaddset(&newsigmask, SIGTERM);
  578.     sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
  579. #else
  580.     int         oldsigmask;
  581.  
  582.     oldsigmask = sigblock(sigmask(SIGHUP) |
  583.                   sigmask(SIGINT) |
  584.                   sigmask(SIGQUIT) |
  585.                   sigmask(SIGTERM));
  586. #endif
  587.  
  588.     signal(SIGHUP, (void (*) ()) sigcatch);
  589.     signal(SIGINT, (void (*) ()) sigcatch);
  590.     signal(SIGQUIT, (void (*) ()) sigcatch);
  591.     signal(SIGTERM, (void (*) ()) sigcatch);
  592.  
  593.     XGrabHosts(dsp);
  594.  
  595. #ifdef SYSV
  596.     sigprocmask(SIG_SETMASK, &oldsigmask, &oldsigmask);
  597. #else
  598.     sigsetmask(oldsigmask);
  599. #endif
  600.     }
  601.     do {
  602.     justDisplay();
  603.     } while (getPassword());
  604. }
  605.  
  606.  
  607. long
  608. allocpixel(cmap, name, def)
  609.     Colormap    cmap;
  610.     char       *name;
  611.     char       *def;
  612. {
  613.     XColor      col;
  614.     XColor      tmp;
  615.     XParseColor(dsp, cmap, name, &col);
  616.     if (!XAllocColor(dsp, cmap, &col)) {
  617.     fprintf(stderr, "couldn't allocate: %s, using %s instead\n",
  618.         name, def);
  619.     XAllocNamedColor(dsp, cmap, def, &col, &tmp);
  620.     }
  621.     return col.pixel;
  622. }
  623.  
  624.  
  625. int
  626. main(argc, argv)
  627.     int         argc;
  628.     char       *argv[];
  629. {
  630.     XSetWindowAttributes xswa;
  631.     XGCValues   xgcv;
  632.     XColor      nullcolor;
  633.  
  634.     ProgramName = strrchr(argv[0], '/');
  635.     if (ProgramName)
  636.     ProgramName++;
  637.     else
  638.     ProgramName = argv[0];
  639.  
  640. #ifdef sco
  641.     set_auth_parameters (argc, argv);
  642. #endif
  643.  
  644.     srandom(time((long *) 0));    /* random mode needs the seed set. */
  645.  
  646.     GetResources(argc, argv);
  647.  
  648.     CheckResources();
  649.  
  650.     font = XLoadQueryFont(dsp, fontname);
  651.     if (font == NULL) {
  652.     fprintf(stderr, "%s: can't find font: %s, using %s...\n",
  653.         ProgramName, fontname, FALLBACK_FONTNAME);
  654.     font = XLoadQueryFont(dsp, FALLBACK_FONTNAME);
  655.     if (font == NULL)
  656.         error("%s: can't even find %s!!!\n", FALLBACK_FONTNAME);
  657.     }
  658.     screens = ScreenCount(dsp);
  659.     if (screens > MAXSCREENS)
  660.     error("%s: can only support %d screens.\n", MAXSCREENS);
  661.     for (screen = 0; screen < screens; screen++) {
  662.     Screen     *scr = ScreenOfDisplay(dsp, screen);
  663.     Colormap    cmap = DefaultColormapOfScreen(scr);
  664.  
  665.     root[screen] = RootWindowOfScreen(scr);
  666.     bgcol[screen] = allocpixel(cmap, background, "White");
  667.     fgcol[screen] = allocpixel(cmap, foreground, "Black");
  668.  
  669.     if (mono || CellsOfScreen(scr) == 2) {
  670.         Scr[screen].pixels[0] = fgcol[screen];
  671.         Scr[screen].pixels[1] = bgcol[screen];
  672.         Scr[screen].npixels = 2;
  673.     } else {
  674.         int         colorcount = NUMCOLORS;
  675.         u_char      red[NUMCOLORS];
  676.         u_char      green[NUMCOLORS];
  677.         u_char      blue[NUMCOLORS];
  678.         int         i;
  679.  
  680.         hsbramp(0.0, saturation, 1.0, 1.0, saturation, 1.0, colorcount,
  681.             red, green, blue);
  682.         Scr[screen].npixels = 0;
  683.         for (i = 0; i < colorcount; i++) {
  684.         XColor      xcolor;
  685.  
  686.         xcolor.red = red[i] << 8;
  687.         xcolor.green = green[i] << 8;
  688.         xcolor.blue = blue[i] << 8;
  689.         xcolor.flags = DoRed | DoGreen | DoBlue;
  690.  
  691.         if (!XAllocColor(dsp, cmap, &xcolor))
  692.             break;
  693.  
  694.         Scr[screen].pixels[i] = xcolor.pixel;
  695.         Scr[screen].npixels++;
  696.         }
  697.         if (verbose)
  698.         fprintf(stderr, "%d pixels allocated\n", Scr[screen].npixels);
  699.     }
  700.  
  701.     xswa.override_redirect = True;
  702.     xswa.background_pixel = BlackPixelOfScreen(scr);
  703.     xswa.event_mask = KeyPressMask | ButtonPressMask | VisibilityChangeMask;
  704.  
  705. #ifdef DEBUG
  706. #define WIDTH WidthOfScreen(scr) - 100
  707. #define HEIGHT HeightOfScreen(scr) - 100
  708. #define CWMASK CWBackPixel | CWEventMask
  709. #else
  710. #define WIDTH WidthOfScreen(scr)
  711. #define HEIGHT HeightOfScreen(scr)
  712. #define CWMASK CWOverrideRedirect | CWBackPixel | CWEventMask
  713. #endif
  714.  
  715.     win[screen] = XCreateWindow(dsp, root[screen], 0, 0, WIDTH, HEIGHT, 0,
  716.                  CopyFromParent, InputOutput, CopyFromParent,
  717.                     CWMASK, &xswa);
  718.  
  719. #ifdef DEBUG
  720.     {
  721.         XWMHints    xwmh;
  722.  
  723.         xwmh.flags = InputHint;
  724.         xwmh.input = True;
  725.         XChangeProperty(dsp, win[screen],
  726.                 XA_WM_HINTS, XA_WM_HINTS, 32, PropModeReplace,
  727.             (unsigned char *) &xwmh, sizeof(xwmh) / sizeof(int));
  728.     }
  729. #endif
  730.  
  731.     iconx[screen] = (DisplayWidth(dsp, screen) -
  732.              XTextWidth(font, text_info, strlen(text_info))) / 2;
  733.  
  734.     icony[screen] = DisplayHeight(dsp, screen) / 6;
  735.  
  736.     xswa.border_pixel = fgcol[screen];
  737.     xswa.background_pixel = bgcol[screen];
  738.     xswa.event_mask = ButtonPressMask;
  739. #define CIMASK CWBorderPixel | CWBackPixel | CWEventMask
  740.     icon[screen] = XCreateWindow(dsp, win[screen],
  741.                      iconx[screen], icony[screen],
  742.                      ICONW, ICONH, 1, CopyFromParent,
  743.                      InputOutput, CopyFromParent,
  744.                      CIMASK, &xswa);
  745.  
  746.     XMapWindow(dsp, win[screen]);
  747.     XRaiseWindow(dsp, win[screen]);
  748.  
  749.     xgcv.foreground = WhitePixelOfScreen(scr);
  750.     xgcv.background = BlackPixelOfScreen(scr);
  751.     Scr[screen].gc = XCreateGC(dsp, win[screen],
  752.                    GCForeground | GCBackground, &xgcv);
  753.  
  754.     xgcv.foreground = fgcol[screen];
  755.     xgcv.background = bgcol[screen];
  756.     xgcv.font = font->fid;
  757.     textgc[screen] = XCreateGC(dsp, win[screen],
  758.                 GCFont | GCForeground | GCBackground, &xgcv);
  759.     }
  760.     lockc = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
  761.     lockm = XCreateBitmapFromData(dsp, root[0], no_bits, 1, 1);
  762.     mycursor = XCreatePixmapCursor(dsp, lockc, lockm,
  763.                    &nullcolor, &nullcolor, 0, 0);
  764.     XFreePixmap(dsp, lockc);
  765.     XFreePixmap(dsp, lockm);
  766.  
  767.  
  768.     if (!enablesaver) {
  769.     XGetScreenSaver(dsp, &sstimeout, &ssinterval,
  770.             &ssblanking, &ssexposures);
  771.     XSetScreenSaver(dsp, 0, 0, 0, 0);    /* disable screen saver */
  772.     }
  773. #ifndef DEBUG
  774.     GrabKeyboardAndMouse();
  775. #endif
  776.  
  777.     nice(nicelevel);
  778.  
  779.     if (nolock)
  780.     justDisplay();
  781.     else
  782.     lockDisplay();
  783.  
  784.     finish();
  785.  
  786.     return 0;
  787. }
  788.